/******************************************************************************/
/** @file    ../user/bsp/
 ** @author  Oscar
 ** @version V2.1
 ** @date    2025-6-16
 ** @brief   soft timer 软件定时器专区.
			 1.Multi Timer 多组软件定时器
				
			 调用自定义库实现
			  * 在CPU空闲函数执行，非阻塞。
			  * 常用于实时性高的场合。
			  * 缺陷：
			  *		(1)比实际时间快0.5%. 
			  * 	(2)因为是在主循环检测超时然后执行回调，所以要尽量避免进程阻塞；
			  * 	(3)占用RAM空间稍多
			  
 ******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include "bsp.h"
#include "bsp_stimer.h"

/* Private includes ----------------------------------------------------------*/
#include <math.h>
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
// 定义定时器链表头指针和平台时钟函数指针
static MultiTimer* timerList = NULL;
static PlatformTicksFunction_t platformTicksFunction = NULL;

/* Private function prototypes -----------------------------------------------*/

/* Private user code ---------------------------------------------------------*/

// 定义软件定时器驱动接口的实例，供外部调用
MultiTimer_driver_t g_bsp_multitimer_inst = {
    .pf_init = multiTimerInstall,  ///< 定时器初始化函数
    .pf_start = multiTimerStart,   ///< 启动定时器函数
    .pf_stop = multiTimerStop,     ///< 停止定时器函数
    .pf_loop = multiTimerYield     ///< 定时器到期处理函数
};

/**
***********************************************************
 * @brief 安装平台时钟函数。 
 * @param ticksFunc 平台时钟函数的指针，返回当前的时钟或计时器值。
 * @return int 返回 0 表示成功，-1 表示失败。
 * @note   用于设置平台时钟函数，通过该函数获取系统时钟或计时器的当前值。
***********************************************************
*/
int multiTimerInstall(PlatformTicksFunction_t ticksFunc) {
    if (ticksFunc == NULL) {
        return -1; // 如果传入的 ticksFunc 为 NULL，则返回失败
    }
    platformTicksFunction = ticksFunc; // 保存平台时钟函数
    return 0;
}

/**
***********************************************************
 * @brief 移除定时器。
 * @param timer 目标定时器的句柄。
 * @note   从定时器列表中移除指定的定时器。这个函数用于定时器停止或超时时的清理工作。
***********************************************************
*/
static void removeTimer(MultiTimer* timer) {
    MultiTimer** current = &timerList;  // 定时器链表的头指针
    while (*current) {
        if (*current == timer) {
            *current = timer->next; // 从链表中移除定时器
            break;  // 找到并移除后退出循环
        }
        current = &(*current)->next; // 遍历到下一个定时器
    }
}
/**
***********************************************************
 * @brief 启动定时器。
 * @param timer 目标定时器句柄。
 * @param timing 定时器的时长，单位为系统时钟周期。
 * @param callback 定时器到期时调用的回调函数。
 * @param userData 用户数据，会传递给回调函数。
 * @return int 如果成功，返回 0；如果失败，返回 -1。
 * @note 启动定时器并将其添加到工作列表中。定时器的回调函数将在定时器到期时被调用。
***********************************************************
*/
int multiTimerStart(MultiTimer* timer, uint32_t timing, MultiTimerCallback_t callback, void* userData) {
    if (!timer || !callback || platformTicksFunction == NULL) {
        return -1; // 如果参数无效，返回错误
    }

    removeTimer(timer);  // 防止定时器重复启动，先移除旧的定时器（如果有）

//    // 补偿定时器的时间误差，将定时器时长略微调整为实际的真实时间
//    uint32_t timing_comp = (uint32_t)round((float)timing / 0.9988f); // 补偿误差，实际时间略微短一些

    // 获取当前系统时钟，并计算定时器的到期时间
    timer->deadline = platformTicksFunction() + timing;
    timer->callback = callback;  // 设置定时器到期时的回调函数
    timer->userData = userData;  // 设置用户数据

    // 将定时器插入到定时器链表中，按到期时间排序
    MultiTimer** current = &timerList;  // 从链表头开始
    while (*current && ((*current)->deadline < timer->deadline)) {
        current = &(*current)->next;  // 遍历到下一个定时器
    }
    timer->next = *current;  // 将新定时器插入到当前定时器后面
    *current = timer;  // 更新链表头指针

    return 0;
}
/**
***********************************************************
 * @brief 停止一个定时器，并将其从定时器工作列表中移除
 * @param timer 目标定时器句柄。
 * @return int 返回 0 表示成功，返回 -1 表示失败。
 * @note  该函数从定时器链表中移除指定的定时器，并停止该定时器的运行。移除后，定时器将不再被执行。
***********************************************************
*/
int multiTimerStop(MultiTimer* timer) {
    removeTimer(timer); // 使用通用移除函数，将定时器从链表中移除
    return 0;
}

/**
***********************************************************
 * @brief  检查并执行到期的定时器回调。即遍历所有已启动的定时器，检查是否有定时器到期。
 *         如果有，到期的定时器会执行回调函数并从定时器列表中移除。
 * @return int 返回下一个定时器的剩余时间，单位为系统时钟周期。如果没有定时器，返回 0。 
 * @note   该函数通常在系统的空闲时间调用，用于执行定时器的超时处理。定时器到期时，会执行相应的回调函数并从链表中移除。
 *         如果没有到期的定时器，函数会返回下一个定时器的剩余时间，表示系统下一个定时器到期的时间。
***********************************************************
*/
int multiTimerYield(void) {
    if (platformTicksFunction == NULL) {
        return -1; // 如果平台时钟函数为空，返回错误
    }

    int32_t currentTicks = platformTicksFunction();  // 获取当前的系统时钟

    // 遍历定时器链表，检查并执行到期的定时器回调
    while (timerList && (currentTicks >= timerList->deadline)) {
        MultiTimer* timer = timerList;  // 获取当前定时器
        timerList = timer->next;  // 将定时器从链表中移除

        if (timer->callback) {
            timer->callback(timer, timer->userData);  // 执行定时器的回调函数
        }
    }

    // 返回下一个定时器的剩余时间。如果没有定时器，则返回 0
    return timerList ? (int)(timerList->deadline - currentTicks) : 0;
}

/**
	
	Example: 
	
	// 创建定时回调函数 Callback functions for the timers
	void timerCallback1(MultiTimer* timer, void* userData) {
		g_bsp_io_inst.pf_led_turn(2);
		g_bsp_multitimer_inst.pf_start(timer, 2, timerCallback1, NULL); // Restart timer
	} 

	// 初始化并传入获取时间回调
	g_bsp_multitimer_inst.pf_init(bsp_GetRunTime);

	// 创建Multi定时器
    MultiTimer timer1, timer2, timer3, timer4;

    // 开启定时器
    g_bsp_multitimer_inst.pf_start(&timer1, 2, timerCallback1, NULL); // 500 ms repeating 

*/
